import math
import random
import time
import sys
from datetime import datetime, timedelta
from typing import Union, List

sys.path.append("../")  # noqa

from api.search.utils import activity_import, role_import

from bson import ObjectId
from pymongo import UpdateOne, MongoClient
from collections import defaultdict

from tqdm import tqdm

from config import settings, col_institution, col_activity, col_alumni, col_register, client, aredis

col_inst = col_institution
activity_col = col_activity
institution_col = col_institution
activity_register_col = col_register
col_person = col_alumni


def update_alumni_score():
    """
    rank_alumni_score:活跃度排名
    prank_alumni_score:后阅读排名百分比
    alumni_score:活跃度
    """
    person_role_score = defaultdict(lambda: 1)
    person_role_score.update(
        {"一般参与": 1, "中等参加": 2, "深度参与": 3, "": 1, None: 1, "中等参与": 2, "中度参与": 2})
    activity_role_score = defaultdict(lambda: 1)
    activity_role_score.update({"常规": 1, "重点": 2, "重大": 3, "": 1, None: 1})

    def cal_identity_value(person_id):
        act_reg = activity_register_col.find({"person_id": ObjectId(person_id)})
        act_reg = list(act_reg)
        activity_id__rolescore_dict = {x["activity_id"]: person_role_score[x.get("level_of_role")] for x in act_reg}
        act_ids = [x["activity_id"] for x in act_reg]
        activity_data = activity_col.find({"_id": {"$in": act_ids}})
        activity_data = list(activity_data)
        activity_id_score_dict = {
            x["_id"]: activity_role_score[x.get("importance_of_activities")] for x in activity_data
        }
        score = 0
        for k, v in activity_id__rolescore_dict.items():
            score += v * activity_id_score_dict[k]
        return score

    person_score_dict = {}
    person_ids = activity_register_col.find({"is_attended": True}, {"person_id": 1}).distinct("person_id")
    for person in tqdm(person_ids):
        person_score_dict[person] = cal_identity_value(person)

    score_list = list(person_score_dict.values())
    score_list.sort(reverse=True)

    person_identity_rank_dict = {}
    person_identity_p_rank_dict = {}
    update_list = []
    for k, v in person_score_dict.items():
        person_identity_rank_dict[k] = score_list.index(v) + 1
        person_identity_p_rank_dict[k] = math.ceil(score_list.index(v) / len(score_list) * 100)
        # rank_alumni_score  排第几名，prank_alumni_score  排名百分比  alumni_score 活跃度
        update_list.append(
            UpdateOne(
                {"_id": k},
                {
                    "$set": {
                        "rank_alumni_score": score_list.index(v) + 1,
                        "prank_alumni_score": math.ceil(score_list.index(v) / len(score_list) * 100),
                        "alumni_score": person_score_dict[k],
                    }
                },
            )
        )
    if update_list:
        col_person.bulk_write(update_list)


def __score_alumni_by_redis(person_ids: Union[List[str], str, None] = None):
    """fixme 解决 circle import 提前 排序的得分写入redis"""
    if isinstance(person_ids, str):
        person_ids = [person_ids]

    _key = f"ranker"
    query = {"is_deleted": {"$ne": True}, "alumni_score": {"$gt": 0}}
    if person_ids:
        query["_id"] = {"$in": [ObjectId(p) for p in person_ids]}

    for person in col_alumni.find(query):
        from_base_dt = person.get("update_time") or datetime.utcnow() - timedelta(days=1)
        member = str(person['_id'])
        _alumni_score = person.get("alumni_score", 1)
        score = int(_alumni_score)
        # 确保float 不重复
        offset = random.random()
        t2 = int((time.time() - from_base_dt.timestamp() + offset) * 1000_1000)
        score = f"{score}.{t2}"
        _mapping = {member: float(score)}
        aredis.zadd(_key, _mapping)


def job_person_score(person_id: str) -> int:
    """计算人的基础分 write mongo and redis """
    register_docs = col_register.find({"person_id": ObjectId(person_id), "is_attended": True},
                                      {"activity_id": 1, "person_id": 1, "level_of_role": 1})

    _score = []
    for reg in register_docs:
        act = col_activity.find_one({"_id": reg["activity_id"], "is_deleted": {"$ne": True}},
                                    {"importance_of_activities": 1})
        if act:
            score_act = act.get("importance_of_activities", "常规")
            score_role = reg.get("level_of_role", "一般参与")
            active_score = activity_import.get(score_act, 1) * role_import.get(score_role, 1)
            _score.append(active_score)

    score = sum(_score) or -1
    col_person.update_one({"_id": ObjectId(person_id)}, {"$set": {"alumni_score": score}})
    __score_alumni_by_redis([person_id])
    return score


if __name__ == "__main__":
    for p in col_person.find({"is_deleted": {"$ne": True}}):
        print(job_person_score
              (str(p["_id"])))
